package com.xms.schema.service.attribute;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.xms.core.exception.XmsException;
import com.xms.datacore.IMetadataProvider;
import com.xms.datacore.service.UpdaterService;
import com.xms.event.core.AuthorizationStateChangedEvent;
import com.xms.event.core.IEventPublisher;
import com.xms.schema.core.AttributeDefaults;
import com.xms.schema.entity.Attribute;
import com.xms.schema.entity.Entity;
import com.xms.schema.extension.AttributeExt;
import com.xms.schema.service.entity.IEntityFinderService;
import com.xms.schema.service.optionset.IOptionSetUpdaterService;
import com.xms.schema.service.relationship.IRelationShipFinderService;
import com.xms.schema.service.stringmap.IStringMapCreaterService;
import com.xms.schema.service.stringmap.IStringMapDeleterService;
import com.xms.utils.CollectionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.sql.SQLException;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * AttributeUpdaterService
 * </p>
 *
 * @author migo
 * @since 2021/9/2
 */
@CacheConfig(cacheNames = "schema.attribute", keyGenerator = "CacheKeyGenerator")
@Service
public class AttributeUpdaterService extends UpdaterService<Attribute> implements IAttributeUpdaterService {
    private IEntityFinderService _entityFinderService;
    private IRelationShipFinderService _relationShipFinderService;
    private IOptionSetUpdaterService _optionSetUpdaterService;
    private IStringMapCreaterService _stringMapCreaterService;
    private IStringMapDeleterService _stringMapDeleterService;
    private IMetadataProvider _metadataProvider;
    private IEventPublisher _eventPublisher;

    @Autowired
    public void AttributeUpdaterService(IEntityFinderService entityFinderService,
                                        IRelationShipFinderService relationShipFinderService,
                                        IOptionSetUpdaterService optionSetUpdaterService,
                                        IStringMapCreaterService stringMapCreaterService,
                                        IStringMapDeleterService stringMapDeleterService,
                                        IMetadataProvider metadataProvider,
                                        IEventPublisher eventPublisher) {
        _entityFinderService = entityFinderService;
        _relationShipFinderService = relationShipFinderService;
        _optionSetUpdaterService = optionSetUpdaterService;
        _stringMapCreaterService = stringMapCreaterService;
        _stringMapDeleterService = stringMapDeleterService;
        _metadataProvider = metadataProvider;
        _eventPublisher = eventPublisher;
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class, isolation = Isolation.READ_UNCOMMITTED)
    @Override
    public boolean update(Attribute entity) throws XmsException, SQLException {
        boolean success = super.update(entity);
        if (success) {
            //选项类型
            if (AttributeExt.typeIsPickList(entity) || AttributeExt.typeIsStatus(entity)) {
                if (entity.getOptionset() != null && !entity.getOptionset().getIspublic()) {
                    entity.getOptionset().setItems(entity.getOptionset().getItems());
                    _optionSetUpdaterService.update(entity.getOptionset());
                }
            }
            //bit类型
            else if (AttributeExt.typeIsBit(entity) || AttributeExt.typeIsState(entity)) {
                if (CollectionUtil.notEmpty(entity.getPicklists()))//bit
                {
                    _stringMapDeleterService.deleteByAttributeId(entity.getAttributeid());
                    _stringMapCreaterService.createMany(entity.getPicklists());
                }
            }
            //如果更新的是name之类的主字段，要找到所有关联视图重建，所以这里直接跳过
            if(!entity.getIsprimaryfield()) {
                Entity parent = _entityFinderService.getById(entity.getEntityid());
                //drop view
                _metadataProvider.dropView(parent);
                //alter column
                _metadataProvider.alterColumn(entity);
                //alter view
                _metadataProvider.alterView(parent,
                        super.list(new LambdaQueryWrapper<Attribute>().eq(Attribute::getEntityid, entity.getEntityid())),
                        _relationShipFinderService.getByReferencingEntityId(entity.getEntityid()));
            }
        }
        return success;
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean updateAuthorization(boolean isAuthorization, List<UUID> id) {
        Assert.notEmpty(id, "id must not be empty");
        boolean success = super.update(new LambdaUpdateWrapper<Attribute>()
                .set(Attribute::getAuthorizationenabled, isAuthorization)
                .in(Attribute::getAttributeid, id));
        if (success) {
            _eventPublisher.publish(new AuthorizationStateChangedEvent(AttributeDefaults.MODULE_NAME, id, isAuthorization));
        }
        return success;
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean updateRequired(boolean state, List<UUID> id) {
        return super.update(new LambdaUpdateWrapper<Attribute>()
                .in(Attribute::getAttributeid, id)
                .eq(Attribute::getIscustomizable, true)
                .set(Attribute::getIsrequired, state));
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean updateLogEnabled(boolean state, List<UUID> id) {
        return super.update(new LambdaUpdateWrapper<Attribute>()
                .in(Attribute::getAttributeid, id)
                .set(Attribute::getLogenabled, state));
    }

    @CacheEvict(allEntries = true, condition = "#result == true")
    @Transactional(rollbackFor=Exception.class)
    @Override
    public boolean updateMany(List<Attribute> entity) throws XmsException, SQLException {
        if (CollectionUtil.notEmpty(entity)) {
            for (Attribute attribute : entity) {
                this.update(attribute);
            }
            return true;
        }
        return false;
    }
}
